﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Linq.Dynamic;

namespace Nikita.Assist.CommonQuery
{
    public static class DynamicLinq
    {
        /// <summary>  创建lambda中的参数,即c=>c.xxx==xx 中的c  
        /// 
        /// </summary>  
        public static ParameterExpression CreateLambdaParam<T>(string name)
        {
            return Expression.Parameter(typeof(T), name);
        }

        /// <summary>   创建linq表达示的body部分,即c=>c.xxx==xx 中的c.xxx==xx  
        ///
        /// </summary>  
        public static Expression GenerateBody<T>(this ParameterExpression param, Filter filterObj)
        {
            PropertyInfo property = typeof(T).GetProperty(filterObj.Key);

            //组装左边  
            Expression left = Expression.Property(param, property);
            //组装右边  
            Expression right = null;
            Expression filter = null;
            Expression expressALL = null;
            if (!filterObj.Contract.Contains("in"))
            {
                bool blnCheckFlag = CheckInput(property.PropertyType, filterObj.Value);
                if (!blnCheckFlag)
                {
                    throw new Exception("输入的值有误");
                }
                //todo: 下面根据需要，扩展自己的类型  
                if (property.PropertyType == typeof(int))
                {
                    right = Expression.Constant(int.Parse(filterObj.Value));
                }
                else if (property.PropertyType == typeof(DateTime))
                {
                    right = Expression.Constant(DateTime.Parse(filterObj.Value));
                }
                else if (property.PropertyType == typeof(string))
                {
                    right = Expression.Constant((filterObj.Value));
                }
                else if (property.PropertyType == typeof(decimal))
                {
                    right = Expression.Constant(decimal.Parse(filterObj.Value));
                }
                else if (property.PropertyType == typeof(Guid))
                {
                    right = Expression.Constant(Guid.Parse(filterObj.Value));
                }
                else if (property.PropertyType == typeof(bool))
                {
                    right = Expression.Constant(filterObj.Value.Equals("1"));
                }
                else
                {
                    throw new Exception("暂不能解析该Key的类型");
                }
            }
            else
            {
                if (filterObj.Contract == "in")
                {
                    string[] strAry = filterObj.Value.Split(',');
                    for (int i = 0; i < strAry.Length; i++)
                    {
                        if (i == 0)
                        {
                            if (property.PropertyType == typeof(string))
                            {
                                expressALL = Expression.Equal(left, Expression.Constant(strAry[i]));
                            }
                            else
                            {
                                expressALL = Expression.Equal(left, Expression.Constant(int.Parse(strAry[i])));
                            }
                        }
                        else
                        {
                            Expression temp = null;
                            if (property.PropertyType == typeof(string))
                            {
                                temp = Expression.Equal(left, Expression.Constant(strAry[i]));
                            }
                            else
                            {
                                temp = Expression.Equal(left, Expression.Constant(int.Parse(strAry[i])));
                            }
                            expressALL = expressALL.Or(temp);
                        }
                    }
                }
                else if (filterObj.Contract == "not in")
                {
                    string[] strAry = filterObj.Value.Split(',');
                    for (int i = 0; i < strAry.Length; i++)
                    {
                        if (i == 0)
                        {
                            if (property == typeof(string))
                            {
                                expressALL = Expression.Equal(left, Expression.Constant(strAry[i]));
                            }
                            else
                            {
                                expressALL = Expression.NotEqual(left, Expression.Constant(int.Parse(strAry[i])));
                            }
                        }
                        else
                        {
                            Expression temp = null;
                            if (property == typeof(string))
                            {
                                temp = Expression.NotEqual(left, Expression.Constant(strAry[i]));
                            }
                            else
                            {
                                temp = Expression.NotEqual(left, Expression.Constant(int.Parse(strAry[i])));
                            }
                            expressALL = expressALL.And(temp);
                        }

                    }
                }
            }
            //todo: 下面根据需要扩展自己的比较  
            if (!filterObj.Contract.Contains("in"))
            {
                filter = Expression.Equal(left, right);
            }
            switch (filterObj.Contract)
            {

                case "=":
                    filter = Expression.Equal(left, right);
                    break;

                case "<>":
                    filter = Expression.NotEqual(left, right);
                    break;


                case ">":
                    filter = Expression.GreaterThan(left, right);
                    break;

                case ">=":
                    filter = Expression.GreaterThanOrEqual(left, right);
                    break;

                case "<":
                    filter = Expression.LessThan(left, right);
                    break;

                case "<=":
                    filter = Expression.LessThanOrEqual(left, right);
                    break;

                case "like":
                    filter = Expression.Call(left, typeof(string).GetMethod("Contains", new[] { typeof(string) }),
                                 Expression.Constant(filterObj.Value));
                    break;

                case "in":
                case "not in":
                    filter = expressALL;
                    break;
            }
            return filter;
        }

        /// <summary>检查输入合法性
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="Value"></param>
        /// <returns></returns>
        private static bool CheckInput(Type type, string Value)
        {
            bool falg = true;
            if (type == typeof(int))
            {
                int result;
                if (!int.TryParse(Value, out result))
                {
                    falg = false;
                }
            }
            else if (type == typeof(DateTime))
            {
                DateTime result;
                if (!DateTime.TryParse(Value, out result))
                {
                    falg = false;
                }
            }
            else if (type == typeof(decimal))
            {
                decimal result;
                if (!decimal.TryParse(Value, out result))
                {
                    falg = false;
                }
            }
            else if (type == typeof(Guid))
            {
                Guid result;
                if (!Guid.TryParse(Value, out result))
                {
                    falg = false;
                }
            }
            else if (type == typeof(bool))
            {
                bool result;
                if (!bool.TryParse(Value, out result))
                {
                    falg = false;
                }
            }
            return falg;
        }

        //public static Func<ObjT, bool> PropertyCheck<ObjT, PropT>(string propertyName, Expression<Func<PropT, bool>> predicate)
        //{
        //    var paramExpr = Expression.Parameter(typeof(ObjT));
        //    var propExpr = Expression.Property(paramExpr, propertyName);
        //    return Expression.Lambda<Func<ObjT, bool>>(Expression.Invoke(predicate, propExpr), paramExpr).Compile();
        //}

        //private static MethodInfo method_Contains =
        //                (from m in typeof(Enumerable).GetMethods()
        //                 where m.Name.Equals("Contains")
        //                     && m.IsGenericMethod
        //                     && m.GetGenericArguments().Length == 1
        //                     && m.GetParameters().Length == 2
        //                 select m
        //                ).First();

        /// <summary>  创建完整的lambda,即c=>c.xxx==xx  
        /// 
        /// </summary>  
        public static LambdaExpression GenerateLambda(this ParameterExpression param, Expression body)
        {
            return Expression.Lambda(body, param);
        }

        /// <summary>  创建完整的lambda，为了兼容EF中的where语句  
        /// 
        /// </summary>  
        public static Expression<Func<T, bool>> GenerateTypeLambda<T>(this ParameterExpression param, Expression body)
        {
            return (Expression<Func<T, bool>>)(param.GenerateLambda(body));
        }

        public static Expression AndAlso(this Expression expression, Expression expressionRight)
        {
            return Expression.AndAlso(expression, expressionRight);
        }

        public static Expression Or(this Expression expression, Expression expressionRight)
        {
            return Expression.Or(expression, expressionRight);
        }

        public static Expression And(this Expression expression, Expression expressionRight)
        {
            return Expression.And(expression, expressionRight);
        }
    }
}
